<?php
/**
 * Created by PhpStorm.
 * User: 11893
 * Date: 2018/11/15
 * Time: 15:51
 */

namespace Mars\PageCache\Drivers;

use Illuminate\Contracts\Foundation\Application;
use Illuminate\Filesystem\Filesystem;
use Mars\PageCache\CacheInterface;
use Mars\PageCache\Exception\PathNotFoundException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class FileCache implements CacheInterface
{
    protected $files;

    protected $cachePath = null;

    protected $app;

    public function __construct(Filesystem $files)
    {
        $this->files = $files;
    }

    public function setApplication(Application $app)
    {
        $this->app = $app;
        return $this;
    }

    public function shouldCache(Request $request)
    {
        return $request->isMethod('GET') && !$this->hasPage($request);
    }

    public function cache(Request $request, Response $response, $expire = 0)
    {
        $file = $this->getCachePathAndName($request);

        if ($response->isSuccessful()) {
            $content = $response->getContent();
            $this->files->put($file, $content, true);
        }
        return $response;
    }

    protected function getDirectoryAndFileNames(Request $request)
    {
        $segments = explode('/', ltrim($request->getPathInfo(), '/'));

        $file = $this->aliasFilename(array_pop($segments)) . '.html';

        return [$this->getCachePath(implode('/', $segments)), $file];
    }

    protected function getCachePathAndName(Request $request = null)
    {
        if (!$this->cachePath) {
            list($path, $file) = $this->getDirectoryAndFileNames($request);
            $this->files->makeDirectory($path, 0775, true, true);
            $this->cachePath = rtrim($path, '/').DIRECTORY_SEPARATOR.$file;
        }
        return $this->cachePath;
    }

    protected function aliasFilename($file)
    {
        return $file ?? 'pc__index';
    }

    protected function getCachePath($path = "")
    {
        return $this->app->make('path.public') . DIRECTORY_SEPARATOR . 'page-cache' . ($path ? DIRECTORY_SEPARATOR . $path : $path);
    }

    public function output(Request $request = null)
    {
        $path = $this->getCachePathAndName($request);
        if (is_null($path)) {
            throw new PathNotFoundException();
        }
        return $this->files->get($path);
    }

    public function hasPage(Request $request)
    {
        return $this->files->exists($this->getCachePathAndName($request));
    }
}